package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	connaddr = "127.0.0.1:8081"
	filename = "fileini.ini"
)

var li = []string{"小米", "华为", "三星", "mac", "windows", "其他"}

var filemap = make(map[string]string)

type file struct {
	filename string
	fileaddr string
}

var filedowns chan string

var dir string

var w sync.WaitGroup

func main() {
	conn, err := net.DialTimeout("tcp", connaddr, 10*time.Second)
	if err != nil {
		fmt.Println("连接服务器失败，", err)
		return
	}
	_, err = conn.Write([]byte("get"))
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	filebuf := bufio.NewScanner(conn)
	for filebuf.Scan() {
		fileinfo := filebuf.Text()
		filesl := strings.Split(fileinfo, ",")
		filemap[filesl[0]] = filesl[1]
	}
	conn.Close()
	//file,err := os.Create(filename)
	//if err != nil{
	//	fmt.Println("创建文件信息列表失败",err.Error())
	//}
	for _, f := range li {
		_, err := os.Stat(f)
		if err != nil {
			err := os.Mkdir(f, os.ModePerm)
			if err != nil {
				fmt.Println("创建", f, "失败！")
				return
			}
		}
	}
	dir, _ := os.Getwd()
	lisAlldir(dir)
	for k, _ := range filemap {
		w.Add(1)
		go getFile(k)
	}
	w.Wait()
}

func lisAlldir(path string) {
	files, _ := ioutil.ReadDir(path)
	for _, fl := range files {
		if fl.IsDir() {
			fmt.Println("搜索目录", fl.Name())
			lisAlldir(path + "/" + fl.Name())
		} else {
			v, ok := filemap[fl.Name()]
			if ok {
				m, _ := strconv.ParseInt(v, 10, 64)
				if m == fl.Size() {
					delete(filemap, fl.Name())
					continue
				}
			}
		}
	}
}

//md5算法，备选方案
/*func getMd5(fl string) string{
	f,err := os.Open(fl)
	if err != nil{
		fmt.Println("计算MD5失败")
		return ""
	}
	defer f.Close()
	r := bufio.NewReader(f)
	h := md5.New()
	_,err := io.Copy(h,r)
	if err != nil{
		return ""
	}
	return fmt.Sprintf("%x",h.Sum(nil))
}
*/
//数据结构
//以0xff开头，后8位byte为数据包长度，1byte存储位置
func getFile(filename string) {
	var shujubuf bytes.Buffer
	conn, err := net.Dial("tcp", connaddr)
	if err != nil {
		fmt.Println("go连接服务器失败")
	}
	defer conn.Close()
	conn.Write([]byte(filename))
	by := make([]byte, 1)
	path := make([]byte, 1)
	_, err = conn.Read(by)
	if err != nil {
		fmt.Println("126读取文件头失败")
		return
	}
	conn.Read(path)
	if by[0] != 0xff {
		fmt.Println("数据包协议失败")
	}
	filelenbtye := make([]byte, 8)
	conn.Read(filelenbtye)
	filelength := binary.BigEndian.Uint64(filelenbtye)
	fmt.Println(filename, "大小", filelength)
	bb := make([]byte, 1024)
	mun := 0
	for {
		n, err := conn.Read(bb)
		if err == io.EOF {
			break
		}
		mun += n
		shujubuf.Write(bb[:n])
	}
	if uint64(mun) != filelength {
		fmt.Println("数据不完整")
		return
	}

	switch path[0] {
	case 0x01:
		file, err := os.Create("小米/" + filename)
		chuliErr(err)
		file.Write(shujubuf.Bytes())
		file.Close()
		fmt.Println(filename + "下载成功")
	case 0x02:
		file, err := os.Create("华为/" + filename)
		chuliErr(err)
		file.Write(shujubuf.Bytes())
		file.Close()
		fmt.Println(filename + "下载成功")
	case 0x03:
		file, err := os.Create("三星/" + filename)
		chuliErr(err)
		file.Write(shujubuf.Bytes())
		file.Close()
		fmt.Println(filename + "下载成功")
	case 0x04:
		file, err := os.Create("windows/" + filename)
		chuliErr(err)
		file.Write(shujubuf.Bytes())
		file.Close()
		fmt.Println(filename + "下载成功")
	case 0x05:
		file, err := os.Create("mac/" + filename)
		chuliErr(err)
		file.Write(shujubuf.Bytes())
		file.Close()
		fmt.Println(filename + "下载成功")
	default:
		file, err := os.Create("其他/" + filename)
		chuliErr(err)
		file.Write(shujubuf.Bytes())
		file.Close()
		fmt.Println(filename + "下载成功")
	}
	w.Done()
}

func chuliErr(err error) {
	if err != nil {
		fmt.Println(err.Error())
	}
}